package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.common.converter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.fasterxml.jackson.databind.JsonNode;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.context.FlowElementProcessContext;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.threadlocal.DeployIdContainer;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.CustomPropertiesProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserTaskActivityProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.SpringUtils;
import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.BaseElement;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.editor.language.json.converter.ActivityProcessor;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.UserTaskJsonConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author lilh
 * @date 2019-03-04 20:17
 */
public class CustomUserTaskJsonConverter extends UserTaskJsonConverter {

    private  static Logger  logger  = LoggerFactory.getLogger(CustomUserTaskJsonConverter.class);

    private FlowElement currentFlowElement;

    public static void fillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {

        fillJsonTypes(convertersToBpmnMap);
        fillBpmnTypes(convertersToJsonMap);
    }

    public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap) {
        convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
    }

    public static void fillBpmnTypes(Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.put(UserTask.class, CustomUserTaskJsonConverter.class);
    }

    @Override
    public void convertToBpmnModel(JsonNode elementNode, JsonNode modelNode, ActivityProcessor processor, BaseElement parentElement, Map<String, JsonNode> shapeMap, BpmnModel bpmnModel) {
        super.convertToBpmnModel(elementNode, modelNode, processor, parentElement, shapeMap, bpmnModel);
        try {
            if (Objects.nonNull(this.currentFlowElement)) {
                //todo 该阶段可以处理节点中的扩展属性，属性值可以从elementNode中获取
                if (currentFlowElement instanceof Activity) {
                    //activity 为已经构建了基本信息的UserTask, elementNode为原始的json节点，activity根据elementNode的信息构建而成
                    Activity activity = (Activity) currentFlowElement;
                    //处理自定义属性节点
                    executeCustomPropertiesProcessor(activity, elementNode, modelNode);
                    //处理会签和非会签场景下设置处理人、候选人、候选组
                    executeUserTaskActivityProcessor(activity, elementNode, modelNode);
                }
            }
        } finally {
            this.currentFlowElement = null;
        }
    }

    private void executeUserTaskActivityProcessor(Activity activity, JsonNode elementNode, JsonNode modelNode) {
        UserTask userTask = (UserTask) activity;
        Map<String, UserTaskActivityProcessor> userTaskActivityProcessorMap = SpringUtils.getApplicationContext().getBeansOfType(UserTaskActivityProcessor.class);
        for (UserTaskActivityProcessor userTaskActivityProcessor : userTaskActivityProcessorMap.values()) {
            if (userTaskActivityProcessor.support(userTask)) {
                try{
                    userTaskActivityProcessor.process(FlowElementProcessContext.builder().deployId(DeployIdContainer.getDeployId())
                            .elementNode(elementNode)
                            .modelNode(modelNode)
                            .nodeCode(activity.getId())
                            .activity(activity)
                            .build()
                    );
                }catch (Exception e){
                    logger.info("ExecuteUserTaskActivityProcessor Error,Reason:"+e.getLocalizedMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    private void executeCustomPropertiesProcessor(Activity activity, JsonNode elementNode, JsonNode modelNode) {
        Map<String, CustomPropertiesProcessor> customPropertiesProcessorMap = SpringUtils.getApplicationContext().getBeansOfType(CustomPropertiesProcessor.class);
        for (CustomPropertiesProcessor propertiesProcessor : customPropertiesProcessorMap.values()) {
            if (propertiesProcessor.support(elementNode)) {
                try{
                    propertiesProcessor.process(FlowElementProcessContext.builder()
                            .deployId(DeployIdContainer.getDeployId())
                            .nodeCode(activity.getId())
                            .elementNode(elementNode)
                            .modelNode(modelNode)
                            .activity(activity)
                            .build());
                }catch (Exception e){
                    logger.info("ExecuteCustomPropertiesProcessor Error,Reason:"+e.getLocalizedMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap) {
        this.currentFlowElement = super.convertJsonToElement(elementNode, modelNode, shapeMap);
        return currentFlowElement;
    }


    @Override
    protected List<String> getValueAsList(String name, JsonNode objectNode) {
        List<String> resultList = new ArrayList();
        JsonNode valuesNode = objectNode.get(name);
        if (valuesNode != null) {
            Iterator var5 = valuesNode.iterator();

            while(var5.hasNext()) {
                JsonNode valueNode = (JsonNode)var5.next();
                resultList.add(valueNode.toString());
            }
        }

        return resultList;
    }
}
